In an ideal situation, our program runs smoothly without any errors. However it is not always the case. Errors may be due to developer's fault or programmer's mistake or of computer. Source of some errors might be hard to undertsand. However it is the task of Good Programmer to handle all kinds of errors that might occur in his program. If some error condition escapes from the developer and user catches it, It is a bug in the program. Developers must update the programs periodically to fix the bugs in the software. You may remember that recent ransomware attack which caused the loss of enormous amount of data, was due to a bug in Microsoft Windows.
Let's write a lambda to divide 2 numbers
In [1]:
div = lambda x,y : x/y
In [2]:
div(8,2)
Out[2]:
In [3]:
div(0/0)
Oh No!... It was a error. Let's handle it.
try
-except
-finally
try-except-finally
provides an easy way to handle errors that can arise during program execution. It works similar to try-catch-finally
blocks in Java
and C#
Syntax:
try:
<statement 1>
<statement 2>
...
<statement n>
except (Exception List): # Refer note
<statement 1>
<statement 2>
...
<statement n>
finally:
<cleanup 1>
<cleanup 2>
...
<cleanup n>
div
with exception handling
In [5]:
def div_good(x,y):
try:
return x/y
except ZeroDivisionError:
print("Division by zero")
In [6]:
div_good(8,2)
Out[6]:
In [7]:
div_good(0,0)
Note how the exception was handled
In [4]:
def div_clean(x,y):
try:
value = x/y
except ZeroDivisionError:
value = float('NaN')
return value
In [2]:
div_clean(4,3)
Out[2]:
In [3]:
div_clean(8,0)
Out[3]:
In [5]:
raise NameError('HiThere')
The sole argument to raise
indicates the exception to be raised. This must be either an exception instance or an exception class (a class that derives from Exception). If an exception class is passed, it will be implicitly instantiated by calling its constructor with no arguments:
In [6]:
raise ValueError # shorthand for 'raise ValueError()'
If you need to determine whether an exception was raised but don’t intend to handle it, a simpler form of the raise
statement allows you to re-raise the exception:
In [7]:
try:
raise NameError('HiThere')
except NameError:
print('An exception flew by!')
raise
Programs may name their own exceptions by creating a new exception class. Exceptions should typically be derived from the Exception
class, either directly or indirectly.
Exception classes can be defined which do anything any other class can do, but are usually kept simple, often only offering a number of attributes that allow information about the error to be extracted by handlers for the exception. When creating a module that can raise several distinct errors, a common practice is to create a base class for exceptions defined by that module, and subclass that to create specific exception classes for different error conditions:
In [1]:
class Error(Exception):
"""Base class for exceptions in this module."""
pass
class InputError(Error):
"""Exception raised for errors in the input.
Attributes:
expression -- input expression in which the error occurred
message -- explanation of the error
"""
def __init__(self, expression, message):
self.expression = expression
self.message = message
class TransitionError(Error):
"""Raised when an operation attempts a state transition that's not
allowed.
Attributes:
previous -- state at beginning of transition
next -- attempted new state
message -- explanation of why the specific transition is not allowed
"""
def __init__(self, previous, next, message):
self.previous = previous
self.next = next
self.message = message
Most exceptions are defined with names that end in Error
, similar to the naming of the standard exceptions.